<!DOCTYPE html>
<html lang="en">
<head>
	<meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0">
  <link rel="shortcut icon" href="../../favicon.ico" type="image/x-icon">
	<title>diffing_key</title>
</head>
<body>
  <div id="test"></div>

  <script type="text/javascript" src="../../js/17/react.development.js" ></script>
  <script type="text/javascript" src="../../js/17/react-dom.development.js"></script>
  <script type="text/javascript" src="../../js/17/babel.min.js"></script>
  <script type="text/javascript" src="../../js/17/prop-types.js"></script>

  <script type="text/babel">
    class Person extends React.Component {
      state = {persons: [
        {id:1, name:"老刘", age: 32},
        {id:2, name:"老李", age: 36}
      ]}

      componentDidMount(){
      }

      add = ()=>{
        const {persons} = this.state
        const newPerson = {id:persons.length+1, name:"小陈", age:18}
        this.setState({
          persons: [newPerson, ...persons]
        })
      }

      /**
       * key: 是虚拟DOM对象的标识. 当状态中的数据发生变化时,react会根据新数据生成新的虚拟DOM. 随后
       * react将新的虚拟DOM与旧的虚拟DOM使用diff进行比较
       * A: 在旧的虚拟DOM中找到了新的虚拟DOM中相同的key.
       *   a: 若key所标识的新的虚拟DOM对象与旧虚拟DOM对象的内容不变,则直接使用旧虚拟DOM已渲染好的真实DOM.
       *   b: 若key所标识的新的虚拟DOM对象与旧虚拟DOM对象的内容有变化,则生成新的真实DOM,替换掉页面之前的真实DOM
       * B: 在旧的虚拟DOM中没有找到新的虚拟DOM中相同的key.
       *   a: 根据新的虚拟DOM生成新的真实DOM.
       * 
       * 若key使用的字段与渲染的内容间的映射关系是可变的,比如循环中的索引值与内容.则可能会出现一些问题.
       *   1, 对已存在的数据集,向其头部增加数据. 则头部的索引为0, 旧数据对应的索引值依次+1.
       * 这就是一种key与内容的映射动态变更的情况
       *   这种情况下: 由于新的虚拟DOM中的key与旧的虚拟DOM中的key存在n个重复,但这n个重复的key所映射的内容都变了,将
       * 导致react的diffing对比n次得到n次不同内容的结论,因此会进行n次生成新的真实DOM的行为,再加上本身新增的一次.最终
       * 会执行n+1次生成新的真实DOM的行为,相当于整个数据集被重新生成了.效率极低.
       *   解决方案:
       *   1), 要么从尾部添加新的数据,不会影响原来的映射关系;
       *   2), 要么使用映射关系不会改变的值作为key,比如数据本身的唯一标识符
       *   2, 如果存在对DOM的数据操作行为,则此类错误代码还会造成错误的DOM更新
       */
      render(){
        return (
          <div>
            <button onClick={this.add}>加上小陈</button>
            <div>
              <h2>使用不稳定的key</h2>
              <ul>
                {
                  this.state.persons.map((e, i)=>{
                   return <li key={i}>{e.name}-{e.age} <input type="text" /></li>
                  })
               }
              </ul>
            </div>
            <div>
              <h2>使用稳定的key</h2>
              <ul>
                {
                  this.state.persons.map((e)=>{
                   return <li key={e.id}>{e.name}-{e.age} <input type="text" /></li>
                  })
               }
              </ul>
            </div>
          </div>
        )
      }
    }

    ReactDOM.render(<Person />, document.getElementById('test'));
  </script>
</body>